package hr.ctg.service;

import hr.ctg.domain.model.Jezik;
import hr.ctg.domain.model.Opis;
import hr.ctg.service.dao.JezikDAO;
import hr.ctg.service.dao.OpisDAO;
import hr.ctg.service.work.Work;
import hr.service.Wiki;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

import javax.faces.context.FacesContext;

import org.htmlparser.Parser;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.ParagraphTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.TextExtractingVisitor;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.async.Asynchronous;
import org.jboss.seam.annotations.async.Expiration;
import org.jboss.seam.annotations.async.IntervalDuration;
import org.jboss.seam.annotations.web.RequestParameter;
import org.jboss.seam.log.Log;

@Name("wikiService")
public class WikiService implements Work {
	public static final int MAX_TEXT_LENGTH = 65535;
	private String domainSuffix = ".wikipedia.org";;

	@In
	JezikDAO jezikDAO;

	@In
	OpisDAO opisDAO;

	@In(required = false)
	FacesContext facesContext;
	@RequestParameter
	String wiki;

	@Logger
	Log log;

	// @Out(required = false)
	// Opis opis;

	public WikiService() {

	}

	public WikiService(final String locale) {
		domainSuffix = locale + domainSuffix;
	}

	// public String getPagePreface(final Object o, final int pNodes,
	// final String lang) {
	// if (o instanceof Mjesto) {
	// final Mjesto mjesto = (Mjesto) o;
	// opis = opisDAO.findByMjestoOznaka(mjesto, lang);
	// } else if (o instanceof Otok) {
	// final Otok otok = (Otok) o;
	// opis = opisDAO.findByOtokOznaka(otok, lang);
	// } else if (o instanceof Zupanija) {
	// final Zupanija zupanija = (Zupanija) o;
	// opis = opisDAO.findByZupanijaOznaka(zupanija, lang);
	// } else if (o instanceof Drzava) {
	// final Drzava drzava = (Drzava) o;
	// opis = opisDAO.findByDrzavaOznaka(drzava, lang);
	// } else if (o instanceof Park) {
	// final Park park = (Park) o;
	// opis = opisDAO.findByParkOznaka(park, lang);
	// }
	//
	// if (opis != null && opis.getOpis() != null) {
	// return getPagePreface(opis.getOpis(), lang, pNodes);
	// }
	//
	// return null;
	// }

	// public String getPagePreface(final Object o, final int pNodes) {
	// final String lang = facesContext.getViewRoot().getLocale()
	// .getLanguage();
	// return getPagePreface(o, pNodes, lang);
	// }

	private String getPagePreface(final String content, /* final String lang, */
	final int pNodes) {
		String out = "";
		try {
			final Parser parser = Parser.createParser(content, "UTF-8");
			final NodeList nodeList = parser.parse(new TagNameFilter("P"));
			final NodeList nlOut = new NodeList();
			for (int i = 0; i < nodeList.size() && i < pNodes; ++i) {
				nlOut.add(nodeList.elementAt(i));
			}
			if (nodeList.size() == 0) {
				// igor dodao kako bi pokrio vrijednosti iz baze
				final ParagraphTag pt = new ParagraphTag();
				final NodeList nl = new NodeList();
				nl.add(new TextNode(content));
				pt.setChildren(nl);
				nlOut.add(pt);
			}

			// final UrlModifyingVisitor urlModifyingVisitor = new
			// LinkUrlModifyingVisitor(
			// "http://" + getDomain(lang));
			// nlOut.visitAllNodesWith(urlModifyingVisitor);
			out = nlOut.toHtml();
		} catch (final ParserException e) {
			e.printStackTrace();
		}
		return out;
	}

	private String getTextPagePreface(final String content) {
		String out = "";
		try {
			final Parser parser = Parser.createParser(content, "UTF-8");
			final TextExtractingVisitor visitor = new TextExtractingVisitor();
			parser.visitAllNodesWith(visitor);
			out = visitor.getExtractedText();
			// Check final length - db field has finite length!!
			if(out.length()>MAX_TEXT_LENGTH)out = out.substring(0, MAX_TEXT_LENGTH-1);
		} catch (final ParserException e) {
			e.printStackTrace();
		}
		return out;
	}

	private String getDomain(final String lang) {
		return lang + domainSuffix;
	}

	private String getPageContent(final String page, final String lang) {
		String content = null;
		try {
			content = new Wiki(getDomain(lang)).getPageHtml(page);
		} catch (final IOException e) {
			log.debug(e.getMessage(), e);
		}

		return content;
	}

	@Asynchronous
	@Transactional
	public void process(@Expiration final Date date,
			@IntervalDuration final long duration) {
		process();
	}

	@Override
	@Asynchronous
	@Transactional
	public void process(@Expiration Date date) {
		process();
	}

	private void process() {
		log.info("WikiService je  poceo s radom");
		final List<Jezik> jl = jezikDAO.findAll();
		List<Opis> lo = new ArrayList<Opis>();
		if (wiki == null) {
			for (final Jezik jezik : jl) {
				lo.addAll(opisDAO.findByWikiNotNullJezik(jezik));
			}
		} else {
			Scanner s = new Scanner(wiki);
			s.useDelimiter(",");
			for (final Jezik jezik : jl) {
				while (s.hasNext()) {
					lo.addAll(opisDAO.findByWikiJezik(s.next(), jezik));
				}
			}
		}
		for (final Opis opis : lo) {
			String page = getPageContent(opis.getWikipedia(), opis.getJezik()
					.getOznaka());
			if (page != null) {
				try {
					page = getPagePreface(page, /* jezik.getOznaka(), */10);
					page = getTextPagePreface(page);
					opis.setZadnjeAzuriranje(new Date());
					opis.setOpis(page);
					opisDAO.merge(opis);
					opisDAO.flush();
				} catch (final Exception e) {
					log.error("update za tablicu opis nije uspio, id=: "
							+ opis.getIdOpisa(), e);
					opis.setOpis(null);
					opisDAO.merge(opis);
					opisDAO.flush();
				}
			}
		}
		log.info("WikiService je  zavrsio s radom");
	}
}